package com.kj.tms.common.utils.calx.util;

import com.kj.tms.common.utils.StringUtil;
import com.kj.tms.common.utils.calx.sheet.Sheet;
import jdk.nashorn.api.scripting.ScriptObjectMirror;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @ProjectName: ledger
 * @Package: com.hongtu.tms.ledger.calx.factory
 * @ClassName: Utility
 * @Description: []
 * @Author: [zhuyongjie]
 * @CreateDate: 2018/4/16 11:24
 * @UpdateUser: []
 * @UpdateDate: 2018/4/16 11:24
 * @UpdateRemark: []
 * @Version: 1.0
 * Copyright: 北京宏图天安 Copyright (c) 2018
 */
public class Utility {
    //Javascript引擎
    private static ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    private static ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("javascript");;
//        this.scriptEngine = this.scriptEngineManager.getEngineByName("nashorn");


    /**
     * @Method      match
     * @Param		rule
     * @Param		formula
     * @Param		globalMatch 是否全局匹配
     * @Return      java.util.List<java.lang.String>
     * @Exception
     * @Description [正则匹配]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/21 9:03
     */
    public static List<String> match(String rule, String formula, boolean globalMatch) {

        List<String> result = new ArrayList<String>();
        Pattern p;
        p = Pattern.compile(rule);
        Matcher m = p.matcher(formula);
        while (m.find()){
            int count = m.groupCount();
            for(int i = 0;i <= count;i ++){
                result.add(m.group(i));
                if(!globalMatch){
                    result.add(StringUtil.toString(m.start()));
                    result.add(formula);
                }
            }
        }
        return result;
    }

    /**
     * @Method execJavascriptMatch
     * @Param rule
     * @Param input
     * @Return java.util.List<java.lang.String> 返回匹配List类型数组
     * @Exception
     * @Description [执行JavaScript String.prototype.match方法]
     * @Author zhuyongjie
     * @Version 1.0
     * @Date 2018/4/13 9:16
     */
    public static List<String> execJavascriptMatch(String rule, String input) {

        List<String> result = new ArrayList<String>();
        //JavaScript执行match的js代码
        StringBuffer js = new StringBuffer();
        js.append("var regex = " + rule + ";");
        js.append("var formula = '" + input.replaceAll("'", "\\\\'") + "';");
        js.append("formula.match(regex);");
        try {
            //执行JavaScript方法并获取返回值
            Object eval = scriptEngine.eval(js.toString());
            if (!StringUtil.isEmptyOrNull(eval)) {
                if (eval instanceof ScriptObjectMirror) {//判断返回值类型
                    ScriptObjectMirror mirror = (ScriptObjectMirror) eval;
                    if (mirror.isArray()) {//判断返回值是否是数组类型
                        for (Map.Entry<String, Object> entry : mirror.entrySet()) {//循环赋值返回值
                            Object value = entry.getValue();
                            if (!StringUtil.isEmptyOrNull(value)) {
                                result.add(entry.getValue().toString());
                            } else {//null值也不落下，保持返回值的完整性
                                result.add(null);
                            }//if end
                        }//for end
                    }//if end
                }//if end
            } else {
                return null;
            }//if end
        } catch (Exception e) {
            e.printStackTrace();
        }//try end
        return result;
    }//execJavascriptMatch end

    /**
     * @Method      cellRange
     * @Param		addressStart
     * @Param		addressStop
     * @Return      java.util.List<java.lang.String>
     * @Exception
     * @Description [获取A1:B4范围内单元格编码]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/16 11:34
     */
    public static List<String> cellRange(String addressStart,
                                         String addressStop)
            throws Exception {
        //单元格范围List
        List<String> cellRange = new ArrayList<>();
        try {
            //单元格英文编码正则
            //String alpha = "/[A-Z]+/";
            String alpha = "[A-Z]+";
            //单元格所在行匹配正则
//            String num = "/[0-9]+/";
            String num = "[0-9]+";
            //开始单元格
            String cellStart = addressStart.toUpperCase();
            //结束单元格
            String cellStop = addressStop.toUpperCase();
            //开始单元格
            //Integer alphaAxisStart = toNum(execJavascriptMatch(alpha, cellStart).get(0));
            Integer alphaAxisStart = toNum(match(alpha, cellStart,false).get(0));
            //结束单元格
            //Integer alphaAxisStop = toNum(execJavascriptMatch(alpha, cellStop).get(0));
            Integer alphaAxisStop = toNum(match(alpha, cellStop,false).get(0));
            //范围开始
            //int numAxisStart = StringUtil.toInt(execJavascriptMatch(num, cellStart).get(0));
            int numAxisStart = StringUtil.toInt(match(num, cellStart,false).get(0));
            //范围结束
            //int numAxisStop = StringUtil.toInt(execJavascriptMatch(num, cellStop).get(0));
            int numAxisStop = StringUtil.toInt(match(num, cellStop,false).get(0));
            String cellAddress = "";

            if(alphaAxisStart > alphaAxisStop){
                //数字交换,确保单元格列顺序正确 B:A,交换后A:B
                alphaAxisStart = alphaAxisStart ^ alphaAxisStop;
                alphaAxisStop = alphaAxisStart ^ alphaAxisStop;
                alphaAxisStart = alphaAxisStart ^ alphaAxisStop;
            }//if end
            if(numAxisStart > numAxisStop){
                //4:3交换后3:4
                numAxisStart = numAxisStart ^ numAxisStop;
                numAxisStop = numAxisStart ^ numAxisStop;
                numAxisStart = numAxisStart ^ numAxisStop;
            }//if end
            for(int col = alphaAxisStart;col <= alphaAxisStop;col ++){
                for(int row = numAxisStart;row <= numAxisStop;row ++){
                    cellAddress = toChr(col) + row;
                    cellRange.add(cellAddress);
                }
            }//for end
//            System.out.println(cellRange.toString());
        }catch (Exception e){
            throw e;
        }//try end

        return cellRange;
    }//cellRange end

    /**
     * @Method      cellRange
     * @Param		addressStart
     * @Param		addressStop
     * @Param		sheet
     * @Return      java.util.List<java.lang.String>
     * @Exception
     * @Description [根据台账获取单元格范围,考虑台账中存在新增行]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/5/7 11:17
     */
    public static List<String> cellRange(String addressStart, String addressStop, Sheet sheet)
            throws Exception{
        List<String> result = new ArrayList<String>();
        try {
            //单元格英文编码正则
            String alpha = "[A-Z]+";
            //单元格所在行匹配正则
            String num = "[0-9]+";
            //开始单元格
            String cellStart = addressStart.toUpperCase();
            //结束单元格
            String cellStop = addressStop.toUpperCase();
            //开始单元格
            Integer alphaAxisStart = toNum(match(alpha, cellStart,false).get(0));
            //结束单元格
            Integer alphaAxisStop = toNum(match(alpha, cellStop,false).get(0));
            //范围开始
            int numAxisStart = StringUtil.toInt(match(num, cellStart,false).get(0));
            //范围结束
            int numAxisStop = StringUtil.toInt(match(num, cellStop,false).get(0));
            String cellAddress = "";
            if(alphaAxisStart > alphaAxisStop){
                //数字交换,确保单元格列顺序正确 B:A,交换后A:B
                alphaAxisStart = alphaAxisStart ^ alphaAxisStop;
                alphaAxisStop = alphaAxisStart ^ alphaAxisStop;
                alphaAxisStart = alphaAxisStart ^ alphaAxisStop;
            }//if end
            if(numAxisStart > numAxisStop){
                //4:3交换后3:4
                numAxisStart = numAxisStart ^ numAxisStop;
                numAxisStop = numAxisStart ^ numAxisStop;
                numAxisStart = numAxisStart ^ numAxisStop;
            }//if end
            List<Map<String, Object>> dataList = sheet.getDataList();
            //开始和结束行
            int start = 0,end = 0;
            for(int i = 0;i < dataList.size();i ++){
                Map<String, Object> data = dataList.get(i);
                int rowno = StringUtil.toInt(data.get("ROWNO"));
                if(rowno == numAxisStart && rowno == numAxisStop){
                    start = i;
                    end = i;
                }else if(rowno == numAxisStart){
                    start = i;
                }else if(rowno == numAxisStop){
                    end = i;
                }//if end
            }//for end
            for(int col = alphaAxisStart;col <= alphaAxisStop;col ++){
                for (int i = start;i <= end;i ++){
                    Map<String, Object> data = dataList.get(i);
                    int rowno = StringUtil.toInt(data.get("ROWNO"));
                    cellAddress = toChr(col) + rowno;
                    result.add(cellAddress);
                }//for end
            }//for end
        }catch (Exception e){
            throw e;
        }
        return result;
    }//cellRange end


    /**
     * @Method      toChr
     * @Param		num
     * @Return      java.lang.String
     * @Exception
     * @Description [数字转字符]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/16 13:58
     */
    public static String toChr(Integer num){
        String s = "";
        num -= 1;
        while (num >= 0){
            s =(char)(num % 26 + 97) + s;
            num = new Double((Math.floor(num / 26) - 1)).intValue();
        }
        return s.toUpperCase();
    }//toChr end

    /**
     * @Method      toNum
     * @Param		str
     * @Return      java.lang.Integer
     * @Exception
     * @Description [字符转换成数字类型 A => 1, B => 2, Z => 26, AA => 27 etc]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/16 14:08
     */
    public static Integer toNum(String str){
        Integer result = 0;
        String[] split = str.split("");
        String[] base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

        for(int i = 0, j = split.length - 1;i < split.length;i ++,j-- ){
            result += new Double(Math.pow(base.length,j)).intValue()
                    * ( arrIndexOf(base,split[i]) + 1 );
        }
        return result;
    }//toNum end

    /**
     * @Method      arrIndexOf
     * @Param		arr
     * @Param		value
     * @Return      int
     * @Exception
     * @Description [元素在数组中的位置]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/16 14:20
     */
    public static int arrIndexOf(String[] arr, String value){
        int index = -1;
        index = Arrays.asList(arr).indexOf(value);
        return index;
    }//arrIndexOf end


    public static void main(String[] args) {

//        System.out.println(toNum("Z"));

//        System.out.println(toChr(26));

       /* try {
            cellRange("AMTA10","AMTB4");
        } catch (Exception e) {
            e.printStackTrace();
        }*/

       String regex = "[A-Z]+[0-9]+";
       String formula = "(A1) + (A2)";
        List<String> match = match(regex, formula,true);
        List<String> strings = execJavascriptMatch("/" + regex + "/g", formula);
        System.out.println(match);
        System.out.println(strings);

    }


    /**
     * @Method      isNumeric
     * @Param		str
     * @Return      boolean
     * @Exception
     * @Description [判断字符串是否是数字]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/12 9:56
     */
    public static boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if( !isNum.matches() ){
            return false;
        }
        return true;
    }

    /**
     * @Method      mapToArray
     * @Param		map
     * @Return      java.lang.String[]
     * @Exception
     * @Description [map转换成String数组]
     * @Author      zhuyongjie
     * @Version     1.0
     * @Date        2018/4/22 20:26
     */
    public static String[] mapToArray(Map<String, Object> map) {
        String[] result = new String[map.size()];
        int a = 0;
        for(Map.Entry<String,Object> entry : map.entrySet()){
            String value = StringUtil.toString(entry.getValue());
            result[a] = value;
            a ++;
        }
        return result;
    }


}
